package com.aichan.aibi.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.aichan.aibi.common.DeleteRequest;
import com.aichan.aibi.common.ErrorCode;
import com.aichan.aibi.constant.CommonConstant;
import com.aichan.aibi.exception.BusinessException;
import com.aichan.aibi.exception.ThrowUtils;
import com.aichan.aibi.mapper.ChartMapper;
import com.aichan.aibi.model.dto.chart.ChartAddRequest;
import com.aichan.aibi.model.dto.chart.ChartQueryRequest;
import com.aichan.aibi.model.dto.chart.ChartUpdateRequest;
import com.aichan.aibi.model.dto.ai.GenChartRequest;
import com.aichan.aibi.model.entity.Chart;
import com.aichan.aibi.model.vo.ChartGenResult;
import com.aichan.aibi.service.ChartService;
import com.aichan.aibi.utils.AiUtils;
import com.aichan.aibi.utils.ExcelUtils;
import com.aichan.aibi.utils.ThreadLocalUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * @author BakaAiChan
 * @description 针对表【chart(图表信息表)】的数据库操作Service实现
 * @createDate 2024-11-16 17:37:23
 */
@Service
public class ChartServiceImpl extends ServiceImpl<ChartMapper, Chart>
        implements ChartService {

    @Resource
    private ChartMapper chartMapper;
    @Resource
    private AiUtils aiUtils;
    @Resource
    @Lazy
    private ChartService chartService;

    @Override
    public void addChart(ChartAddRequest chartAddRequest) {
        Chart chart = new Chart();
        BeanUtil.copyProperties(chartAddRequest, chart);
        chart.setUserId(ThreadLocalUtil.getUserId());
        boolean save = this.save(chart);
        ThrowUtils.throwIf(!save, ErrorCode.SYSTEM_ERROR, "新增失败！数据库异常！");
    }

    @Override
    public void updateChart(ChartUpdateRequest chartUpdateRequest) {
        Chart chart = new Chart();
        BeanUtil.copyProperties(chartUpdateRequest, chart);
        boolean update = this.updateById(chart);
        ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR, "更新失败！数据库异常！");
    }

    @Override
    public void deleteChart(DeleteRequest deleteRequest) {
        boolean remove = this.removeById(deleteRequest.getId());
        ThrowUtils.throwIf(!remove, ErrorCode.SYSTEM_ERROR, "删除失败！数据库异常！");
    }

    @Override
    public Page<Chart> getChartPage(ChartQueryRequest chartQueryRequest) {
        Long id = chartQueryRequest.getId();
        String name = chartQueryRequest.getName();
        String goal = chartQueryRequest.getGoal();
        String chartData = chartQueryRequest.getChartData();
        String chartType = chartQueryRequest.getChartType();
        Long userId = chartQueryRequest.getUserId();
        long current = chartQueryRequest.getCurrent();
        long pageSize = chartQueryRequest.getPageSize();
        String sortField = chartQueryRequest.getSortField();
        String sortOrder = chartQueryRequest.getSortOrder();

        LambdaQueryWrapper<Chart> lqw = new LambdaQueryWrapper<>();
        lqw.eq(id != null, Chart::getId, id)
                .like(!StrUtil.isBlankIfStr(name), Chart::getName, name)
                .like(!StrUtil.isBlankIfStr(goal), Chart::getGoal, goal)
                .like(!StrUtil.isBlankIfStr(chartData), Chart::getChartData, chartData)
                .like(!StrUtil.isBlankIfStr(chartType), Chart::getChartType, chartType)
                .eq(userId != null, Chart::getUserId, userId);
        if (!StrUtil.isBlankIfStr(sortField)) {
            lqw.orderBy("createTime".equals(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), Chart::getCreateTime);
        }
        return this.page(new Page<>(current, pageSize), lqw);
    }

    @Override
    public ChartGenResult genResultFormUserDataByAI(MultipartFile multipartFile, GenChartRequest genChartRequest) {
        ChartGenResult result = new ChartGenResult();
        String name = genChartRequest.getName();
        String goal = genChartRequest.getGoal();
        String chartType = genChartRequest.getChartType();
        // 1.异步插入数据库
        ChartAddRequest chartAddRequest = new ChartAddRequest();
        chartAddRequest.setName(name);
        chartAddRequest.setGoal(goal);
        chartAddRequest.setChartType(chartType);
        CompletableFuture<Long> saveResult = chartService.saveToDBBySync(chartAddRequest, ThreadLocalUtil.getUserId());
        // 2.文件校验
        if (multipartFile == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "上传的文件为空！");
        }
        String originalFilename = multipartFile.getOriginalFilename();
        if (originalFilename == null || !(originalFilename.endsWith(".xlsx") || originalFilename.endsWith(".csv"))) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "上传的文件格式错误，应为.xlsx或.csv格式！");
        }
        // 3.xlsx转csv
        String excelData = null;
        try {
            excelData = ExcelUtils.excelToCsv(multipartFile);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户文件解析失败！");
        }
        // 4.AI生成
        String dataToMakeAiGen = String.format("分析需求：\n %s \n原始数据：\n%s \n 指定的图表名称：\n%s \n 指定的图表类型，注意如果数据和图表类型差异过大则选择合适数据的图表类型：\n%s", goal, excelData, name, chartType);
        String aiGen = null;
        try {
            aiGen = aiUtils.doStableRequest(CommonConstant.prompt, dataToMakeAiGen);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI生成失败！");
        }
        // 4.1 对AI生成的数据进行处理
        int firstFlag = aiGen.indexOf("【【【【【") + 4;
        int lastFlag = aiGen.lastIndexOf("【【【【【");
        String genChart = aiGen.substring(firstFlag + 1, lastFlag);
        // 4.2 拼接最外层大括号
        genChart = "{" + genChart.substring(2, genChart.length() - 2) + "}";
        // 4.3 将单引号替换为双引号，使其符合JSON格式
        genChart = genChart.replace("'", "\"");
        String genResult = aiGen.substring(lastFlag + 5);
        // 4.4 填充结果
        result.setGenChart(genChart);
        result.setGenResult(genResult);
        // 5.异步更新数据库
        ChartUpdateRequest chartUpdateRequest = new ChartUpdateRequest();
        try {
            // 5.1 获取之前异步插入数据库时返回的Chart Id
            chartUpdateRequest.setId(saveResult.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        chartUpdateRequest.setChartData(excelData);
        chartUpdateRequest.setGenChart(genChart);
        chartUpdateRequest.setGenResult(genResult);
        chartUpdateRequest.setStatus("done");
        chartService.updateToDBBySync(chartUpdateRequest);
        // TODO 失败重试操作
        return result;
    }

    /**
     * 这里是异步操作，所以和用户连接的线程不是同一个线程，所以不能通过ThreadLocal获取userId，需要显性的传递userId。
     */
    @Override
    @Async
    public CompletableFuture<Long> saveToDBBySync(ChartAddRequest chartAddRequest, Long userId) {
        Chart chart = new Chart();
        BeanUtil.copyProperties(chartAddRequest, chart);
        chart.setUserId(userId);
        chart.setStatus("wait");
        boolean save = this.save(chart);
        ThrowUtils.throwIf(!save, ErrorCode.SYSTEM_ERROR, "新增失败！数据库异常！");
        return CompletableFuture.completedFuture(chart.getId());
    }

    @Override
    @Async
    public void updateToDBBySync(ChartUpdateRequest chartUpdateRequest) {
        Chart chart = new Chart();
        BeanUtil.copyProperties(chartUpdateRequest, chart);
        chart.setStatus("done");
        boolean update = this.updateById(chart);
        ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR, "更新失败！数据库异常！");
    }


}




